﻿using DnD.Common;
using DnD.Model;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Maps.Controls;
using Microsoft.Phone.Tasks;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Device.Location;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Windows.Devices.Geolocation;
using Windows.Storage;

namespace DnD.ViewModels
{
    class MapViewModel : INotifyPropertyChanged
    {

        private int _zoomLevel;
        private PhoneApplicationPage _view;
        private Map _map;
        private GeoCoordinate _currentPosition;

        public ObservableCollection<DnDMapElement> MapElements { get; set; }
        public DelegateCommand ZoomInCommand { get; set; }
        public DelegateCommand ZoomOutCommand { get; set; }
        public DelegateCommand CaptureCommand { get; set; }

        public int ZoomLevel
        {
            get { return _zoomLevel; }
            set
            {
                _zoomLevel = value;
                OnPropertyChanged();

            }
        }


        public Map GPSMap
        {
            get { return _map; }
            set
            {
                _map = value;
                OnPropertyChanged();
                ZoomInCommand.CanExecute(_map.ZoomLevel);
                ZoomOutCommand.CanExecute(_map.ZoomLevel);
                CaptureCommand.CanExecute(_map);
                refreshMapOverlay();
            }
        }

        public MapViewModel(PhoneApplicationPage view)
        {
            _view = view;

            ZoomInCommand = new DelegateCommand(zoomIn, name => (_map != null) && (_map.ZoomLevel < 20));
            ZoomOutCommand = new DelegateCommand(zoomOut, name => (_map != null) &&  (_map.ZoomLevel > 1));
            CaptureCommand = new DelegateCommand(capture, name => (_map != null) );

            _zoomLevel = 5;
        }

        public void zoomOut(object name)
        {
            if (_map.ZoomLevel > 1)
            {
                _map.ZoomLevel = _map.ZoomLevel - 1;
                ZoomInCommand.CanExecute(_map.ZoomLevel);
                ZoomOutCommand.CanExecute(_map.ZoomLevel);
            }

        }

        public void zoomIn(object name)
        {

            if (_map.ZoomLevel < 20)
            {
                _map.ZoomLevel = _map.ZoomLevel + 1;
                ZoomInCommand.CanExecute(_map.ZoomLevel);
                ZoomOutCommand.CanExecute(_map.ZoomLevel);
            }

        }

        public async void capture(object name)
        {
            Geolocator geolocator = new Geolocator();
            geolocator.DesiredAccuracy = PositionAccuracy.High;
            geolocator.MovementThreshold = 20;

            Geoposition myGeoposition = await geolocator.GetGeopositionAsync();
            _currentPosition = new GeoCoordinate(myGeoposition.Coordinate.Latitude, myGeoposition.Coordinate.Longitude);

            //geolocator.PositionChanged += geolocator_PositionChanged;
            //geolocator.StatusChanged += geolocator_StatusChanged;

            CameraCaptureTask photoChooserTask = new CameraCaptureTask();
            photoChooserTask.Completed += new EventHandler<PhotoResult>(cameraCaptureTask_Completed);
            photoChooserTask.Show();


        }

        async void cameraCaptureTask_Completed(object sender, PhotoResult e)
        {
            if (e.TaskResult == TaskResult.OK)
            {

                DnDMapElement newElement = new DnDMapElement();
                newElement.PositionLatitude = _currentPosition.Latitude;
                newElement.PositionLongitude = _currentPosition.Longitude;

                using (var context = new DnDDataContext(DnDDataContext.DbConnectionString))
                {
                    context.MapElements.InsertOnSubmit(newElement);
                    context.SubmitChanges();

                    newElement.PictureName = "photo"+newElement.Id.ToString();
                    context.SubmitChanges();
                }

                DnDRestService restService = new DnDRestService();

                //await restService.UploadImage(ReadToEnd(e.ChosenPhoto));


                await SaveToLocalFolderAsync(e.ChosenPhoto, newElement.PictureName);
                    //await LoadFromLocalClick();
                    //counter++;

            }
        }

        public static byte[] ReadToEnd(System.IO.Stream stream)
        {
            long originalPosition = 0;

            if (stream.CanSeek)
            {
                originalPosition = stream.Position;
                stream.Position = 0;
            }

            try
            {
                byte[] readBuffer = new byte[4096];

                int totalBytesRead = 0;
                int bytesRead;

                while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
                {
                    totalBytesRead += bytesRead;

                    if (totalBytesRead == readBuffer.Length)
                    {
                        int nextByte = stream.ReadByte();
                        if (nextByte != -1)
                        {
                            byte[] temp = new byte[readBuffer.Length * 2];
                            Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
                            Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
                            readBuffer = temp;
                            totalBytesRead++;
                        }
                    }
                }

                byte[] buffer = readBuffer;
                if (readBuffer.Length != totalBytesRead)
                {
                    buffer = new byte[totalBytesRead];
                    Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
                }
                return buffer;
            }
            finally
            {
                if (stream.CanSeek)
                {
                    stream.Position = originalPosition;
                }
            }
        }



        public async Task SaveToLocalFolderAsync(Stream file, string fileName)
        {
            StorageFolder localFolder = ApplicationData.Current.LocalFolder;
            StorageFile storageFile = await localFolder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
            using (Stream outputStream = await storageFile.OpenStreamForWriteAsync())
            {
                await file.CopyToAsync(outputStream);
            }

            refreshMapOverlay();
        }

        public async Task AddOverlayToMap(string pictureName, GeoCoordinate coordinate)
        {
            try
            {
                StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
                StorageFile testFile = await storageFolder.GetFileAsync(pictureName);

               
                MapLayer mapLayer = new MapLayer();

                Polygon polygon = new Polygon();
                polygon.Points.Add(new Point(0, 0));
                polygon.Points.Add(new Point(200, 0));
                polygon.Points.Add(new Point(200, 200));
                polygon.Points.Add(new Point(20, 200));
                polygon.Points.Add(new Point(0, 230));

                //SolidColorBrush borderBrush = new SolidColorBrush(Colors.Orange);
                //polygon.Fill = borderBrush;

                //Polygon polygon2 = new Polygon();
                //polygon2.Points.Add(new Point(10, 10));
                //polygon2.Points.Add(new Point(190, 10));
                //polygon2.Points.Add(new Point(190, 190));
                //polygon2.Points.Add(new Point(10, 190));
              
                BitmapImage tn = new BitmapImage();
                //tn.SetSource(Application.GetResourceStream(new Uri(e.OriginalFileName, UriKind.Absolute)).Stream);
                tn.SetSource(await testFile.OpenStreamForReadAsync());
                ImageBrush brush = new ImageBrush();
                brush.ImageSource = tn;


                polygon.Fill = brush;

               
                MapOverlay overlay = new MapOverlay();
                overlay.Content = polygon;
                overlay.GeoCoordinate = coordinate;
                //rateszi a terkepre
                overlay.PositionOrigin = new Point(0, 1);

                //MapOverlay overlay2 = new MapOverlay();
                //overlay2.Content = polygon2;
                //overlay2.GeoCoordinate = coordinate;
                //overlay2.PositionOrigin = new Point(0, 2);

                mapLayer.Add(overlay);
                //mapLayer.Add(overlay2);
                GPSMap.Layers.Add(mapLayer);

            }
            catch (Exception e)
            {
                MessageBox.Show("Error while reading.");
                Debug.WriteLine(e.ToString());
            }
        }

        public async void refreshMapOverlay()
        {

            using (var context = new DnDDataContext(DnDDataContext.DbConnectionString))
            {
                MapElements = new ObservableCollection<DnDMapElement>(context.MapElements);
            }

            GPSMap.Layers.Clear();

            foreach (DnDMapElement elem in MapElements)
            {
                await AddOverlayToMap(elem.PictureName, new GeoCoordinate(elem.PositionLatitude, elem.PositionLongitude));

            }



        }

        public void handleMenuRequest(String menuItemName)
        {
            if (menuItemName == "login")
            {
                
            }
            

        }

        


        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }

    }
}
